from typing import Optional

import uvicorn
from fastapi import FastAPI, Body
from fastapi.openapi.docs import get_swagger_ui_html
from pydantic import BaseModel, Field
from starlette.staticfiles import StaticFiles

# 创建 FastAPI 应用实例，并把默认的/docs请求禁用
# debug表示是否开启调试模式，默认是False
app = FastAPI(docs_url=None,debug=True)
app.mount("/static", StaticFiles(directory="../static"), name="static")    # 静态文件

@app.get("/docs", include_in_schema=False)
def custom_swagger_ui():
    return get_swagger_ui_html(
        openapi_url = "/openapi.json",
        title = "Swagger UI for FastAPI",
        swagger_js_url="/static/swagger-ui-bundle.min.js",
        swagger_css_url="/static/swagger-ui.min.css"
    )

class Address(BaseModel):
    # 这里examples是给一个列表是为你的字段可能是一个列表，为了统一所以这里要求提供一个列表
    # 对于非列表的娄据，你给了一个列表超过一个元素也只会取第一个元素作为示例数据
    provice: str = Field(..., max_length=50,examples=['广州'])
    city: str = Field(..., max_length=50)
    region: str = Field(..., max_length=50)
    address: str = Field(..., max_length=255)

class User(BaseModel):
    username: str = Field(..., max_length=10, examples=['张三'])
    description: Optional[str] = Field(None, max_length=128)
    address: Address

    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "username": "李四",
                    "description": "李四的描述",
                    "address": {
                        "provice": "北京",
                        "city": "北京",
                        "region": "朝阳区",
                        "address": "XXX街道XXX号XXX栋XXX号"
                    }
                }
            ]
        }
    }

@app.post("/users")
async def create_user(user: User):
    user_dict = user.model_dump()
    print("user:", user_dict)
    address_dict = user.address.model_dump()
    print("address:", address_dict)
    return user_dict


class Order(BaseModel):
    order_no: str = Field(..., max_length=50)
    price: float = Field(..., ge=0, le=10000)

@app.post("/orders")
# 对于非模型数据中的参数，我们要指定示例数据可以使用Body参数
# 在参数最前面加上*,表示后面的所有参数都是关键字参数，此时调用这个函数必须用传关键字的方式调用
# 注意:一旦我们的参数都变为了关键字参数则就没有前面的有默认值后面的就必须要有这样的要求了！！！因为调用者是用关键字来指定的不存在顺序问题了
async def create_order(*, order: Order=Body(...,examples=[{"order_no": "SO001001001","price": 20.99}]),count:int = Body(...,ge=1,le=1000,examples=[1])):
    order_dict = order.model_dump()
    print("order:", order_dict)
    return order_dict | {'count': count} | {'total': order.price * count}





if __name__ == '__main__':
    uvicorn.run("main:app", host="127.0.0.1", port=8006, reload=True)